import React, { useMemo, useState } from 'react';
import { Button, message, Upload } from 'antd';
import moment from 'moment';
import _ from 'lodash';
import classNames from 'classnames';
import np from '@/utils/numberPrecision';
import { CheckCircleOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { TjModal } from '@/tjComponents/TjModal';
import { TjModalTitle } from '@/tjComponents/TjModal/TjModalTitle';
import TjUploadErrorContent from '../TjUploadErrorContent';
// @ts-ignore
import request from '#/utils/requestAbort';
import { HttpCode } from '#/utils/contacts.js';
import type { ReactNode } from 'react';
import type { RcFile, UploadFileStatus, UploadProps } from 'antd/es/upload/interface';
import './index.less';

const { Dragger } = Upload;

const defaultDraggerProps: UploadProps = {
  name: 'file',
  multiple: false,
  showUploadList: false,
  maxCount: 1,
};

const formatSize = (size: number) => {
  if (size < 1024) return `${size} B`;
  if (size < np.times(1024, 1024)) return `${np.divide(size, 1024).toFixed(2)} KB`;
  return `${np.divide(size, np.times(1024, 1024)).toFixed(2)} MB`;
};

export const downloadFileForFront = (response: BlobPart, fileName: string) => {
  const blob = new Blob([response]);
  const url = window.URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.setAttribute('download', fileName);
  document.body.appendChild(link);
  link.click();
  link.remove();
  window.URL.revokeObjectURL(url);
};

const TjUploadContent: React.FC<ITjUploadContentProps> = (props) => {
  const [fileInfo, setFileInfo] = useState<IFileInfoType>();
  const [originalFile, setOriginalFile] = useState<RcFile>();
  const [loading, setLoading] = useState<boolean>(false);

  const buildAccept = useMemo(() => {
    let str = props.acceptTips;

    if (!props.acceptTips) {
      if (props.accept) {
        const arr = props.accept.split(',');
        const newArr: string[] = [];
        const mergeFileType = ['doc', 'xls', 'ppt'];
        arr.forEach((v) => {
          let n = v.split('.')[1];
          if (mergeFileType.indexOf(n) > -1) {
            n = `${n}x`;
          }
          if (newArr.indexOf(n) < 0) {
            newArr.push(n);
          }
        });
        if (newArr.length === 1) {
          str = `仅支持${newArr[0]}文件`;
        }
        if (newArr.length === 2) {
          str = `仅支持${newArr[0]}文件或${newArr[1]}文件`;
        }
        if (newArr.length > 2) {
          str = `仅支持${newArr.join('、')}等文件`;
        }
      }
    }

    return str;
  }, [props.accept]);

  const beforeUpload: UploadProps['beforeUpload'] = (file: RcFile, FileList: RcFile[]) => {
    let fileInfo: IFileInfoType = {
      name: file.name,
      size: file.size,
      uid: file.uid,
      lastModifiedDate: file.lastModifiedDate,
      uploadDate: moment().format('YYYY-MM-DD HH:mm:ss'),
      // status: 'error',
      // tipsMsg: '错误了错误了错误了错误了错误了错误了错误了错误了错误了错误了',
    };

    if (props.beforeUploadRule && _.isFunction(props.beforeUploadRule)) {
      fileInfo = props.beforeUploadRule(file);
    }

    setFileInfo(fileInfo);
    setOriginalFile(file);
    return false;
  };

  const delFile = () => {
    setOriginalFile(undefined);
    setFileInfo(undefined);
  };

  const showMore = () => {
    TjModal.open({
      title: <TjModalTitle title="文件上传错误内容查看" />,
      width: 500,
      content: <TjUploadErrorContent errorMsg={fileInfo?.tipsMsg} />,
      footer: null,
    });
  };

  const downloadTemplate = () => {
    // 待完善
    const downloadTemplateObj: IDownloadTemplateType = _.get(props, 'downloadTemplate', undefined);
    if (downloadTemplateObj && downloadTemplateObj.url) {
      const method = _.get(downloadTemplateObj, 'method', 'GET');
      request(downloadTemplateObj.url, { method: method, responseType: 'blob' }).then(
        (res: any) => {
          downloadFileForFront(res, downloadTemplateObj.templateName);
        },
      );
    }
  };

  const submit = () => {
    if (originalFile && props.uploadUrl) {
      const uploadFileKey = _.get(props, 'uploadFileKey', 'file');
      setLoading(true);
      const formData = new FormData();
      formData.append(uploadFileKey, originalFile);
      if (props.uploadOtherParams && Object.keys(props.uploadOtherParams).length > 0) {
        for (const i in props.uploadOtherParams) {
          formData.append(i, props.uploadOtherParams[i]);
        }
      }
      request(props.uploadUrl, { data: formData, method: 'POST' })
        .then((res: any) => {
          if (res.statusCode === HttpCode.SUCCESS) {
            message.success('上传成功');
            onCancel();
            props.uploadSuccessCb && props.uploadSuccessCb();
          } else {
            message.error('上传失败');
            const newFileInfo = { ...fileInfo } as IFileInfoType;
            newFileInfo.status = 'error';
            const errorMsg = _.get(res, 'data', _.get(res, 'message', ''));
            newFileInfo.tipsMsg = errorMsg;
            setFileInfo(newFileInfo);
          }
        })
        .finally(() => {
          setLoading(false);
        });
    }
  };

  const onCancel = () => {
    props.onCancel && props.onCancel();
  };

  return (
    <div className="tj-upload-content">
      {props.hearder && <div className="tj-upload-header">{props.hearder}</div>}

      <div className="label">
        导入文件 <span className="tips">{buildAccept}</span>
      </div>

      {props.downloadTemplate && props.downloadTemplate.url && (
        <div className="label">
          下载模板
          <span className="template-name" onClick={downloadTemplate}>
            {props.downloadTemplate?.templateName}
          </span>
        </div>
      )}

      <div className="content">
        {!fileInfo && (
          <Dragger {...defaultDraggerProps} beforeUpload={beforeUpload}>
            <p className="opt-tips">
              <span className="left">点击上传 </span>
              <span className="right">/ 拖拽到此区域</span>
            </p>
          </Dragger>
        )}

        {fileInfo && (
          <div className={classNames('file-info', { error: fileInfo.status === 'error' })}>
            <div className="name">
              {fileInfo.name}
              <span className="icon">
                {fileInfo.status === 'error' ? (
                  <ExclamationCircleOutlined />
                ) : (
                  <CheckCircleOutlined />
                )}
              </span>
            </div>
            <div className="item">文件大小：{formatSize(fileInfo.size)}</div>
            <div className="item">上传日期：{fileInfo.uploadDate}</div>
            <Button type="link" onClick={delFile} loading={loading}>
              删除
            </Button>
          </div>
        )}
      </div>

      {fileInfo && fileInfo.tipsMsg && (
        <div className="tips-msg">
          {fileInfo.tipsMsg.length >= 30 ? (
            <>
              {`${fileInfo.tipsMsg.slice(0, 30)}...`}
              <Button type="link" onClick={showMore}>
                更多
              </Button>
            </>
          ) : (
            fileInfo.tipsMsg
          )}
        </div>
      )}

      <div className="btns">
        {!fileInfo && (
          <Button onClick={onCancel} loading={loading}>
            取消
          </Button>
        )}
        {fileInfo && (
          <>
            <Button onClick={onCancel} loading={loading}>
              取消
            </Button>
            <Button
              type="primary"
              disabled={fileInfo.tipsMsg ? true : false}
              onClick={submit}
              loading={loading}
            >
              提交
            </Button>
          </>
        )}
      </div>
    </div>
  );
};

export interface IFileInfoType {
  /**
   * 当前导入状态目前只处理了error
   */
  status?: UploadFileStatus;
  /**
   * 提示信息、报错提示信息
   */
  tipsMsg?: string;
  /**
   * 文件名称（antd上传自带）
   */
  name: string;
  /**
   * 文件大小（antd上传自带）
   */
  size: number;
  /**
   * 唯一标识符（antd上传自带）
   */
  uid: string;
  /**
   * 文件上一次修改时间（antd上传自带）
   */
  lastModifiedDate: Date;
  /**
   *  选择文件时的时间（前端获取加入）
   */
  uploadDate: string;
}

export interface IDownloadTemplateType {
  /**
   * 导入url，若是路径参数直接拼接好后传入
   */
  url: string;
  /**
   * 导出模板的名字
   */
  templateName: string;
  /**
   * 导出模板用到的其他参数（目前该功能没做，预留该类型）
   */
  otherParams?: Record<string, any>;
  /**
   * 导出是否是浏览器自动导出，若后端响应头content-disposition:attachment则需要调用前端手动在下一次
   */
  browserAutoExport?: boolean;
  /**
   * 自动请求的方式
   */
  method?: 'GET' | 'POST';
}

export interface ITjUploadContentProps {
  /**
   * 上传的url
   */
  uploadUrl: string;
  /**
   *  成功的回调
   */
  uploadSuccessCb?: () => void;
  /**
   *  上传时文件流对映后端的key值 默认是file
   */
  uploadFileKey?: string;
  /**
   *  上传用到其他参数
   */
  uploadOtherParams?: Record<string, any>;
  /**
   * 顶部节点插槽
   * 个别页面导入顶部会有一些筛选框
   */
  hearder?: ReactNode;
  /**
   *  导入文件限制文件类型，原生能力，传入后可自动生成文字说明
   */
  accept?: string;
  /**
   *  说明导入文件类型、传入accept会自动生成，但该字段优先级更高
   */
  acceptTips?: string;
  /**
   *  上传前的校验
   */
  beforeUploadRule?: (file: RcFile) => IFileInfoType;
  /**
   * 导出模板配置
   */
  downloadTemplate?: IDownloadTemplateType;
  /**
   * onCancel
   */
  onCancel?: () => void;
}

export { TjUploadContent };
